package sys.knot.data.access;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sys.knot.interpreter.ResultSetInterpreter;
import sys.knot.model.QuerySpecification;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Date;
import java.util.List;

public class QueryTask implements Runnable {

    private ResultQueue resultQueue;
    private NamedDataSource dataSource;
    private String sql;
    private List<Object> orderedParameters;
    private ResultSetInterpreter interpreter;
    private String queryName;

    private Logger logger;

    public QueryTask(NamedDataSource dataSource,
                     QuerySpecification querySpecification,
                     List<Object> orderedParameters,
                     ResultQueue resultQueue) {
        resultQueue.registerTask();

        this.dataSource = dataSource;
        this.sql = querySpecification.getSql();
        this.orderedParameters = orderedParameters;
        this.resultQueue = resultQueue;
        this.interpreter = querySpecification.getResultSetInterpreter();
        this.queryName = querySpecification.getName();

        logger = LoggerFactory.getLogger(QueryTask.class.getName() + ":" + queryName + "." +dataSource.getName());

    }

    @Override
    public void run() {

        try (Connection connection = dataSource.getDataSource().getConnection()) {

            PreparedStatement preparedStatement = connection.prepareStatement(sql);
            int index = 1;
            for (Object parameter : orderedParameters) {
                if (parameter instanceof String) {
                    logger.debug("Adding string parameter: {}", parameter);
                    preparedStatement.setString(index, (String) parameter);
                } else if (parameter instanceof Integer) {
                    logger.debug("Adding integer parameter: {}", parameter);
                    preparedStatement.setInt(index, (int) parameter);
                } else if (parameter instanceof Date) {
                    logger.debug("Adding date parameter: {}", parameter);
                    preparedStatement.setDate(index, new java.sql.Date(((Date) parameter).getTime()));
                }
//                else if (parameter instanceof String[]) {
//                    Array sqlArray = connection.createArrayOf("text", (String[]) parameter);
//                    System.out.println(sqlArray.toString());
//
//                    preparedStatement.setArray(index, sqlArray);
//                } else if (parameter instanceof int[]) {
//                    Array sqlArray = connection.createArrayOf("number", (Integer[]) parameter);
//                    preparedStatement.setArray(index, sqlArray);
//                }

                else {
                    //TODO handle
                    logger.error("Unknown type of parameter: {}", parameter);
                    throw new Exception("Exception while adding parameters to query...");
                }
                index++;
            }

            ResultSet resultSet = preparedStatement.executeQuery();


            interpreter.addMetaData(dataSource.getName(), queryName, resultSet.getMetaData());
            while(resultSet.next()) {
                resultQueue.put(interpreter.interpretRow(resultSet));
            }

        } catch (Exception e) {
            resultQueue.addErrorMessage("Query failed in data source: " + dataSource.getName() + " (" + e.getClass().getSimpleName() + ")");
            logger.error(dataSource.getName() + ": " + e.getMessage(), e);
        } finally {
            resultQueue.unRegisterTask();
        }
    }

}